Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

文件格式 File Formats

常见的存储数据的文件格式:

CSV

纯文本文件,包含一行行数据(逗号分隔)。

A plain text file contains rows of data (comma separated values)。

例子:

1
2
Sherlock Holmes,221B Baker Street,Detective
James Moriarty,Reichenbach Falls,Villain
  • 简单、可读性好
  • 非常流行、应用广
  • 但细节很多
  • 分隔符可自定义(如用 Tab 的 TSV)
  • 字段里若含有分隔符需要加引用(引号)
  • 如果字符串内部再包含引号,需要转义:"string with "" inside"
  • 适合:扁平表格数据(行列结构),与 Excel/数据库导入导出;不适合复杂嵌套。

XML

一种用于编码(半)结构化数据的文本格式。

A text format encoding (semi-)structured data。

例子

1
2
3
4
<characters>
<person name=“Sherlock Holmesaddress=“221B Baker Streetjob=“Detective”/>
<person name=“James Moriartyaddress=“Reichenbach Fallsjob=“Villain”/>
</characters>
  • 格式本身比 CSV 标准化得更好
  • 也适合表示嵌套数据
  • 人类可读,但不太好手写
  • 冗长,完整 XML 规范也很复杂
  • 支持高级特性(如 XML Schema),但不常用
  • 有一定流行度,但在走下坡路

JSON

源自 JavaScript 对象表示法的文本格式。

A text format stemming from JavaScript Object Notation。

例子

1
2
3
4
5
[
{"name":"Sherlock Holmes", "address":"221B Baker Street", "job":"Detective"},
{"name":"James Moriarty", "address":"Reichenbach Falls", "job":"Villain"}
]

  • 用途与 XML 类似
  • 但格式更简单
  • 更不啰嗦(verbose)、更易书写
  • 正在变得越来越流行

命令行工具 Command Line Tools

Text files are quite popular because they are human readable and easy to use.

这部分主要讲如何利用命令行工具处理txt文件。

组合工具(Combining Tools)

每个程序都有一个输入流(input stream)以及输出流(output stream)。可以将多个命令组合起来:

  • 把两个命令连接起来(Concatenating both):

    1
    command 1 | command 2
  • 把输出重定向到文件(Redirecting to a file):

    1
    command > file
  • 从文件重定向为输入(Redirecting from a file):

    1
    command < file
  • 错误流(error stram):

    1
    command 2 > /dev/null
    • Unix 流编号:0—标准输入 stdin,1—标准输出 stdout,2—标准错误 stderr。
    • command 的错误流重定向到空设备 /dev/null(像“黑洞”一样,会丢弃输入)。

读取文件(Reading Files): cat

  • 读取单个文件:

    1
    cat file
  • 连接多个文件:

    1
    cat file1 file2 file3
  • 接受管道输入:

    1
    command | cat
  • 转义/可视化二进制数据:

    1
    cat -v binaryfile
  • 处理压缩文件:

    1
    zcat / bzcat / xzcat
  • 主要用作其他命令的输入

分页查看结果(Paging reults):less

  • 用于检查结果或文件,分页显示,可向前向后滚动。

  • 在管道中通常用作最后一个命令。

  • 分页命令输出:

    1
    command | less
  • 分页查看文件:

    1
    less file
  • 截断长行:

    1
    less -S

过滤(Filtering):grep

  • 返回所有匹配行——功能强大、选项众多。

  • 过滤输入:

    1
    cat file1 file2 | grep 'img[0-9]*\.jpg'
  • 过滤文件:

    1
    grep 'img[0-9]*\.jpg' *.html
  • 只返回匹配片段:

    1
    command | grep -o 'user=.*$'
  • 返回不匹配的行:

    1
    grep -v '^warning' logfile
  • 不区分大小写:

    1
    cat file | grep -i '\.jpg' file

排序(Sorting):sort

  • 按某种准则对输入排序

    • 基本排序:

      1
      cat file | sort
    • 数字排序:

      1
      cat file | sort -n
    • 按特定键排序:

      1
      cat file | sort -k 2

      以第 2 列开始直到行尾作为排序键进行排序(默认字典序,升序,按空白分隔列;多个空格/Tab 会被合并为一个分隔符,前导空白被忽略)。

    • 指定分隔符排序:

      1
      cat file | sort -t ',' -k 3

      把逗号当作列分隔符,用从第3列到行尾的内容按字典序排序。

    • 排序并去重:

      1
      cat file | sort -u
  • 非常强大且有用

  • 能处理大于内存的文件
  • 已排序的文件可作为其他算法的输入

选前/后缀(Selecting Prefix/Sufix):head / tail

  • 返回文件开头/结尾

    • 前 20 条:

      1
      head -20 file
      1
      sort file | head -20

      这两条命令的结果是不一样的

    • 后 15 条:

      1
      sort file | tail -15
    • 除前两条外的全部:

      1
      sort file | tail -n +3
    • 除最后两条外的全部:

      1
      sort file | head -n -2
  • 这些都是top-k查询——先排序再 head/tail

  • 也可用于最小/最大值计算。

处理重复(Handling Duplicates):uniq

  • 处理已排序输入中的重复:

    • 去重:

      1
      sort file | uniq
    • 计数重复:

      1
      sort file | uniq -c
    • 仅返回重复行:

      1
      sort file | uniq -d
    • 仅返回唯一行:

      1
      sort file | uniq -u
  • 对分组与计数很有用

投影列(Projection Columns):cut

  • 语法:

    1
    cut OPTION... [FILE]...
  • 只返回输入中相关部分

    • 返回特定字段:

      1
      cat file | cut -f 1,3
    • 指定分隔符切分:

      1
      cat file | cut -f 2-4 -d ','
  • 按字符位置切分:

    1
    cat file | cut -c 1-10

计数(Counting):wc

  • 统计行/词/字符数量:

    • 全量统计:

      1
      cat file | wc
    • 只数行数

      1
      cat file | wc -l
    • 只数字节数

      1
      cat file | wc -c
  • 有助于收集数据统计。

乱序(Shuffling):shuf

  • 将输入的行打乱生成随机排列:

    • 随机顺序:

      1
      cat file | shuf
  • 不太常用,但在某些场景很有用:

    • 随机抽样

      1
      cat file | shuf | head -10000
  • 适合性能测试。

编辑文本(Editing Text):sed

  • 语法:

    1
    sed 's/regex/repl/flags'
    • ssubstitute(替换)的意思。
    • 第 1 个分隔符后是正则(要匹配的内容),第 2 个分隔符后是替换文本,最后是标志位(可选)。
    • 默认每行只替换第 1 处匹配;加 g 才是“本行全替”。
    • &替换文本里表示“整段匹配的内容”;\1\2… 表示捕获组
    • sed 的默认正则是 BRE(Basic Regular Expressions):分组要写 \( \);如果用 -E(或 GNU -r),就变成 ERE 分组可用 ( )
  • 用一个文本替换另一个文本:

    • 基本替换:

      1
      2
      3
      cat file | sed 's/oldText/newText/'

      sed 's/oldText/newText/' file

      每一行,把第一次出现oldText 替换成 newText。只影响每行第一个匹配,后面的同一行匹配保持不变。

    • 替换所有出现

      1
      cat file | sed 's/oldText/newText/g'
    • 反向引用

      1
      cat file | sed 's/IMG_\([0-9]*\).JPG/image\1.jpg/g'

      把诸如 IMG_123.JPG 转为 image123.jpg

      • IMG_:字面匹配。
      • \([0-9]*\):捕获组(因为是 BRE 要写 \( \))。匹配零个或多个数字;匹配到的数字被记为组 1
      • 替换串 image\1.jpg:把组 1(即数字)插回去。
      • g:该行所有匹配都替换。
    • 不区分大小写匹配:

      1
      cat file | sed 's/file[0-9]*.png/"&"/I'
    • 使用多个规则

      1
      cat file | sed -e 's/old1/new1/' -e 's:a/b:a_b:'
  • 极其强大且有用;

  • 还有分组、条件分支等更多特性,但很少用。

合并文件(Combining Files):join

  • 合并已排序输入文件:

    • 按公共字段合并两个文件:

      1
      join -1 2 -2 1 file1 file2

      file1 的第2列与 file2 的第1列作为“键”做内连接

      • -1 2:指定 file1 的键列是第 2 列。
      • -2 1:指定 file2 的键列是第 1 列。
      • 没有指定分隔符 ⇒ 用空白切列;多个空白算一个分隔;前导空白被忽略。
      • 没有 -a/-v内连接(仅输出两边都出现的键)。
    • 指定分隔符合并:

      1
      join -1 2 -2 1 -d ',' file1 file2
  • 保留未匹配行(-a):

    1
    join -1 2 -2 1 -a 1 file1 file2
  • 行为类似关系型连接;但如果需要更强功能,可能应使用更强大的工具。

  • 选项说明:

    • -1 FIELD:file1 以该字段连接;-2 FIELD:file2 以该字段连接
    • -a 1 左外连接;-a 2 右外连接;-a 1 -a 2 全外连接
    • -v 抑制已连接的输出行:-v 1 左反连接;-v 2 右反连接

计算(Computation):awk

  • 为输入的每一行执行程序

    • 通用结构:

      1
      awk 'BEGIN{init}{per-line}END{done}' file
    • 计数行数:

      1
      awk 'BEGIN{x=0}{x=x+1}END{print x}'
    • 累加某列:

      1
      awk 'BEGIN{x=0}{x=x+$2}END{print x}'
    • 求某列平均:

      1
      awk 'BEGIN{x=0;y=0}{x+=\$2;y+=1}END{print x/y}'
    • 条件:

      1
      awk 'BEGIN{x=0}{if ($1>10) x+=\$2}END{print x}'